#include "common.h"

int currentSequenceNumber;		
int expectedFinalSequenceNumber;
int socketfd;

long power(int num, int power) {
  long result = num;
  int i = 1;
  for(; i < power; i++) {
    result = result * num;
  }
  if(power == 0) {
    result = 1;
  }
  return result;
}


int handleSynMessage(unsigned char * message, char * fileName, short seqNum, char * address, unsigned short port, unsigned long * fileSize) {
//void handleSynMessage(unsigned char * message, struct addressPort senderInfo) {

		

	if (debug) {
		//printf("handleSynMessage function: Receiving data from %s : %d\n", ipToString(senderInfo.address), senderInfo.port);	
	}

	int index = 2;
  int secondByte, firstByte;
	/*
  firstByte = message[index++] * 16;
  secondByte = message[index++];
	iseqn = firstByte + secondByte;
	*/
	
	printf("first byte %02x", message[index]);
	printf("second byte %02x\n", message[index+1]);
	
	unsigned short iseqn;
	unsigned short * tmpNumA;
	void * ptrA = (void *) message+index;
	tmpNumA = (unsigned short *) ptrA;
	iseqn = htons(* tmpNumA);
	
	index += 2;
	int i;
	for(i = index; i < 25; i++) {
		if(message[i] == '\0') {
			index = i + 1;
			break;
		}
	}
	
	/*
  i = index;
  int bytes = 0;
  while(message[i] != 0) {
    bytes++;
    i++;
  }
  //i is the index that is 0, i-- is index of last byte of size.                                                                            
  i--;
  index = i;
  i = 0;
  fileSize = 0;
  while(bytes != 0) {
    fileSize += message[index] * power(16, i);
    index--;
    bytes--;
    i++;
  }
	*/
	unsigned long fs;
	unsigned long * tmpNum;
	void * ptr = (void *) message+index;
	tmpNum = (unsigned long *) ptr;
	fs = htonl(* tmpNum);
	
	fileSize = (unsigned long *) fs;
	
	if (debug) {
		printf("iseqn is %d fileSize is %ld\n", iseqn, fs); 
	}
	
	return iseqn;

}

int handleAckMessage(unsigned char * sentMsg, unsigned char * recvMsg, struct addressPort senderInfo, struct messageInfo msgInfo) {

	if (debug) {
		printf("handleAckMessage function: Received an ACK.\n");
	}
	
	short seqNum;
	short * tmpNum;
	void * ptr = (void *) recvMsg+2;
	tmpNum = (short *) ptr;
	seqNum = htons(* tmpNum);
	
	if(seqNum == ((currentSequenceNumber+(msgInfo.messagePayloadSize)+1)%65535)) {
		currentSequenceNumber += (msgInfo.messagePayloadSize)+1;
		if(currentSequenceNumber > 65535 ) {
			currentSequenceNumber = currentSequenceNumber % 65535;
			return 1;
		}
		else { return 0; }
	}	
	else {
		sendUDP(ipToString(senderInfo.address), senderInfo.port, socketfd, sentMsg, msgInfo.messageLength);	
		return 0;	
	}
}

void handleFinMessage(unsigned char * message, struct addressPort senderInfo) {

}

/**
 * Creates a data message to be sent to the receiver.
 *
 * @param dataMessage The data message buffer.
 * @param filename The filename to be sent to the receiver.
 * @param seqn The sequence number by byte.
 * @param messageLength The maximum length of the message in bytes.
 * @param filePosition The number of bytes offset from the beginning of the file.
 * @return Returns the size of the message in bytes.
 */
void createDataMessage(unsigned char * dataMessage, char * filename, unsigned short seqn, unsigned short messageLength, long int filePosition, struct messageInfo * msgInfo) {

	if (debug) {
		printf("Entering createDataMessage\n");
	}

	memset(dataMessage, 0, sizeof(dataMessage));

	int currentPosition, i;
	dataMessage[0] = 0xDD;
	currentPosition = 1;
	
	unsigned short * s = (unsigned short *) &dataMessage[currentPosition];
	*s = htons(seqn);
	currentPosition += 2;
	
	// Insert a 2-byte sequence number into data message.
	//currentPosition = sizeToBytes(seqn, dataMessage, currentPosition);
	//currentPosition += 2;
	
	strcpy(dataMessage+currentPosition, filename);
	// Add 1 for the additional '\0' character.
	currentPosition += strlen(filename) + 1;
	
	// Data message has a fixed header length of 3 + filename + 1 (for NULL terminating character) + 2 for 2-byte content length.
	int payloadSize = messageLength - (3 + strlen(filename) + 1 + 4);
	
	// Insert a 4-byte content length (payload) into data message.
	currentPosition = sizeToBytes(payloadSize, dataMessage, currentPosition);
	//currentPosition += 2;
	
	// Open the file to be transmitted.
  FILE * file = fopen(filename, "rb");
  if (file == NULL) {
    perror("Invalid File\n");
    exit(1);
  }

	int c, d = 0;
	
	if (debug) {
		printf("d is %d, payloadSize is %d, currentPosition is %d, filePosition is %ld\n", d, payloadSize, currentPosition, filePosition);
	}
	
	// Point to where the transmission has left off within the file.
	fseek(file, filePosition, SEEK_SET);
	
	
	for (d = 0; d < payloadSize; d++) {
		if ((c = fgetc(file)) != EOF) {
			dataMessage[currentPosition] = c;
			currentPosition++;
			//printf("%d : %c\n", d, c);
		}
		else {
			break;
		}
	}
	
	fclose(file);
	
	msgInfo->messageLength = currentPosition;
	msgInfo->messagePayloadSize = payloadSize;
	
	
	if (debug) {
		printf("Exiting createDataMessage\n");
	}
}

/**
 * Creates a SYN message to be sent to the receiver.
 *
 * @param synMessage The SYN message buffer.
 * @param filename The filename to be sent to the receiver.
 * @param seqn The sequence number by byte.
 * @param fileSize The file size in bytes.
 * @return Returns the size of the message in bytes.
 */
void createSynMessage(unsigned char * synMessage, char * filename, unsigned short seqn, long int fileSize, struct messageInfo * msgInfo) {

	memset(synMessage, 0, sizeof(synMessage));
	
	synMessage[0] = 0xCC;
	synMessage[1] = 0xAA;
	int currentPosition = 2;
	
	unsigned short * s = (unsigned short *) &synMessage[currentPosition];
	*s = htons(seqn);
	currentPosition += 2;

	
	// Insert a 2-byte sequence number into syn message.
	//currentPosition = sizeToBytes(seqn, synMessage, currentPosition);
	
	strcpy(synMessage+currentPosition, filename);
	// Add 1 for the additional '\0' character.
	currentPosition += strlen(filename) + 1;
	
	// Insert a 4-byte file size into syn message.
	currentPosition = sizeToBytes(fileSize, synMessage, currentPosition);
	//currentPosition += 2;
	
	msgInfo->messageLength = currentPosition;
	msgInfo->messagePayloadSize = 0;
	
	if (debug) {
		printf("I'm exiting createSynMessage\n");
	}
}


/**
 * Creates a FIN message to notify the relrecv application that relsend has
 * decided to close the transmission process.
 *
 * @param filename The filename that the sender was sending to the receiver.
 * @return Returns the size of the message in bytes.
 */
int createFinMessage(unsigned char * finMessage, char * filename) {
	
	memset(finMessage, 0, sizeof(finMessage));
	
	finMessage[0] = 0xCC;
	finMessage[1] = 0xEE;
	int currentPosition = 2;
	strcpy(finMessage+currentPosition, filename);
	currentPosition += strlen(filename) + 1;
	
	return currentPosition;
}

/**
 * Creates an ACK message used by relrecv to notify it has or has not receive the next
 * packet in the transmission process.
 *
 * @param ackMessage The ACK message buffer.
 * @param filename The filename that is being transmitted to relrecv.
 * @param ackn The next sequence number in bytes relrecv is expecting from relsend.
 * @return Returns the size of the message in bytes.
 */
int createAckMessage(unsigned char * ackMessage, char * filename,  unsigned short ackn) {
	
	memset(ackMessage, 0, sizeof(ackMessage));
	
	ackMessage[0] = 0xCC;
	ackMessage[1] = 0xAF;
	int currentPosition = 2;
	
	// Insert sequence number into ack message.
	currentPosition = sizeToBytes(ackn, ackMessage, currentPosition);
	//currentPosition += 2;
	
	// Insert filename ack message.
	strcpy(ackMessage+currentPosition, filename);
	currentPosition += strlen(filename) + 1;
	
	return currentPosition;
}

/**
 * Performs bit-shifting for multi-byte values.
 *  
 * @param fileSize The length in bytes of the file.
 * @param pos The index position of where to perform bit-shifting value into.
 * @returns The new index position in the buffer.
 */
int sizeToBytes(long fileSize, char * buffer, int pos) {
  
	if(fileSize > 0 && fileSize < 256) {
		buffer[pos] = 0;
		pos++;
		buffer[pos] = 0;
		pos++;
		buffer[pos] = 0;
		pos++;
    buffer[pos] = fileSize;
    pos++;
    return pos;
  }
  if(fileSize > 255 && fileSize < 65380) {
    int secondByte;
    secondByte = formatNumberByte(fileSize, 8);
		buffer[pos] = 0;
		pos++;
		buffer[pos] = 0;
		pos++;
    buffer[pos] = secondByte;
    buffer[pos + 1] = fileSize;
    pos += 2;
    return pos;
  }
  if(fileSize > 65380) {
    int thirdByte;
    int secondByte;
    thirdByte = formatNumberByte(fileSize, 16);
    secondByte = formatNumberByte(fileSize, 8);
		buffer[pos] = 0;
    buffer[pos + 1] = thirdByte;
    buffer[pos + 2] = secondByte;
    buffer[pos + 3] = fileSize;
    pos += 4;
    return pos;
  }
}

int formatNumberByte(int size, int hex) {
  return size>>hex;
}